
/*
	(c) Galustyan Sergey 2009
*/

#include "dxut.h"
#include "Spheres.h"

namespace TestTask
{
	SphereRender::SphereRender( PDevice device, float radius, Vector3 position, Color color, XHandle render ):
		RenderObject( position, color, render ),radius(radius)
	{
		createSphere( radius, device, mesh );
	}

	float SphereRender::getRadius(){
		return radius;
	}

	ArrowManipulator::ArrowManipulator( PDevice device, Vector3 axis ):
		RenderObject( axis*50.0f, Color(0.5f,0.5f,0.5f,1.0f) ),
		drugging(false),axis(axis),hover(false)
	{
		subsetCount = 2;

		createArrow( device, mesh );
		computeAABB( mesh, aabb_min, aabb_max);

		SetScale( 25.0f );
	
		D3DXMatrixIdentity( &rotation );
		D3DXMatrixIdentity( &iden );

		if ( axis.x > 0 ) D3DXMatrixRotationY( &rotation, -hpi );      
		if ( axis.y > 0 ) D3DXMatrixRotationX( &rotation, hpi );        
		if ( axis.z > 0 ) D3DXMatrixRotationX( &rotation, -pi );        

		ApplyTransform();
	}

	void ArrowManipulator::Render(RenderPackage& rp)
	{
		Vector3 ray_orig, ray_direction;
		Vector3 wray_orig, wray_direction;
		
		getRayFromCamera( &ray_orig, &ray_direction, worldMatrix, rp.view, rp.proj );
		getRayFromCamera( &wray_orig, &wray_direction, iden, rp.view, rp.proj );

		Vector3 point;
		bool intersect = intersectsRay( ray_orig, ray_direction, aabb_min, aabb_max, point);

		// pretty nice alrogithm
		if (hover)
		{
			onedrug = true;
			if (rp.isDrugged)
			{
				Vector3 dif = (wray_direction - prev_direction)*300.0f;
				Vector3 offset = Vector3(dif.x*axis.x,dif.y*axis.y,dif.z*axis.z);
				
				if (master) master->Move(offset);
				else Move(offset);
				
				drugging = true;
			} 
		}
	
		if (!intersect && !drugging && hover) 
			hover = onedrug = false;
		
		if (!rp.isDrugged) 
		{
			drugging = false;
			if ( intersect && !onedrug) hover = true;
		}
		
		if (hover) diffuse = Color(1,0,0,1);
		else diffuse = Color(0.5f,0.5f,0.5f,1.0f);
		
		RenderObject::Render(rp);
		prev_direction = wray_direction;
	}

	bool	ArrowManipulator::onedrug = false;
	Matrix	ArrowManipulator::iden;

	SuperSphere::SuperSphere( PDevice device, float radius, Vector3 position, Color color, PBorder border):border(border),
		SphereRender(device,radius,position,color,"RenderSphere")
	{
		Append( PRenderObject( new ArrowManipulator( device, Vector3(1,0,0) )));
		Append( PRenderObject( new ArrowManipulator( device, Vector3(0,1,0) )));
		Append( PRenderObject( new ArrowManipulator( device, Vector3(0,0,1) )));
		
		ApplyTransform();
	}

	void SuperSphere::Move( Vector3& offset )
	{
		Vector3 suggest;
		border->GetMoveHere( position - Vector3(0,0,getRadius())+ offset, suggest );
		SetPosition( suggest + Vector3(0,0,getRadius()) );	
		ApplyTransform();
	}				

	namespace
	{
		struct Vertex
		{
			FLOAT x, y, z; 
			DWORD color;        
			static const int fvf = (D3DFVF_XYZ|D3DFVF_DIFFUSE);
		};
	}

	LineRender::LineRender( PDevice device, PRenderObject obj1, PRenderObject obj2 ):
		RenderObject( zero, Color(), "RenderLine" ),
		o1(obj1),o2(obj2)
	{
		createVertexBuffer<Vertex>( device, 2, vertexBuffer );
	}

	void LineRender::Render( RenderPackage& rp )
	{
		RenderObject::Render( rp );

		const Vector3& p1 = o1->GetPosition();
		const Vector3& p2 = o2->GetPosition();

		Vertex vertices[] =
		{
			{ p1.x,  p1.y, p1.z, 0xffff00ff, },
			{ p2.x,  p2.y, p2.z, 0xffff00ff, }
		};

		writeVertexBuffer<Vertex>( vertices, 2, vertexBuffer );
		renderVertexBuffer<Vertex>( rp.device, vertexBuffer, D3DPT_LINELIST, 0, 1 );
	}

	void sphereToSphereAxis( PSphereRender s1, PSphereRender s2, Vector3& dir, Vector3& up, Vector3& right, Vector3& orig, Vector3& target)
	{
		target = s1->GetPosition();
		orig = s2->GetPosition();
		dir = target - orig;
		D3DXVec3Normalize( &dir, &dir );
		forward_axis( dir, up, right );
	}
}
